package controllers

import (
	"encoding/json"
	"errors"
	"fmt"
	"goravel/app/jobs"
	"goravel/app/models"
	"time"

	"github.com/goravel/framework/auth"
	"github.com/goravel/framework/contracts/http"
	"github.com/goravel/framework/contracts/mail"
	"github.com/goravel/framework/contracts/queue"
	"github.com/goravel/framework/facades"
	"github.com/goravel/framework/filesystem"
	"github.com/goravel/framework/support/carbon"
	"github.com/goravel/framework/support/debug"
	"github.com/goravel/framework/support/path"
)

type SqqqController struct {
}

func NewSqqqController() *SqqqController {
	return &SqqqController{
		//Inject services
	}
}

// 文件存储
func (c *SqqqController) Filestorage(ctx http.Context) http.Response {

	// 文件上传处理
	// file, err := ctx.Request().File("avatar")
	// path, err := file.Store("avatars_dir")
	// path, err := file.StoreAs("avatars_dir", "new_avatar_name")

	// name := file.GetClientOriginalName()  // 文件名称
	// extension := file.GetClientOriginalExtension() // 文件扩展名
	// name := file.HashName()            // 生成一个唯一的随机名称...
	// extension, err := file.Extension() // 根据文件的 MIME 类型确定文件的扩展名...

	// 目录下的所有文件
	// directories, err := facades.Storage().Disk("s3").Directories("directory")
	// directories, err := facades.Storage().Disk("s3").AllDirectories("directory")

	// 目录的创建和删除
	// err := facades.Storage().MakeDirectory(directory) // 创建目录
	// err := facades.Storage().DeleteDirectory(directory) // 删除目录

	// 文件删除
	// err := facades.Storage().Delete("file.jpg", "file2.jpg")

	// 文件复制,移动
	// err := facades.Storage().Copy("old/file.jpg", "new/file.jpg")
	// err := facades.Storage().Move("old/file.jpg", "new/file.jpg")

	// 将app/common/hello.txt文件保存到photos目录下，并重命名
	file, err := filesystem.NewFile(path.Storage("app/common/hello.txt"))
	if err != nil {
		panic(err.Error())
	}
	path, err := facades.Storage().PutFile("photos", file)
	// path, err := facades.Storage().PutFileAs("photos", file, "newfile.txt")
	if err != nil {
		panic(err.Error())
	}
	fmt.Println("文件create: ", path) // storage\app\file.jpg

	// 文件路径
	path2 := facades.Storage().Path("file.jpg")
	fmt.Println("文件路径: ", path2) // storage\app\file.jpg

	// 文件meta信息
	size, err := facades.Storage().Size("./common/hello.txt")
	if err != nil {
		panic(err.Error())
	}
	time, err := facades.Storage().LastModified("./common/hello.txt")
	if err != nil {
		panic(err.Error())
	}
	mime, err := facades.Storage().MimeType("./common/hello.txt")
	if err != nil {
		panic(err.Error())
	}
	fmt.Println("文件meta信息: ", size, time, mime)

	// 文件地址
	url := facades.Storage().Url("common/file.jpg") // /common/file.jpg
	fmt.Println(url)

	// 1.保存到文件
	facades.Storage().Put("common/hello.txt", "sbjsw")
	facades.Storage().Disk("public").Put("upload.txt", "sbjsw")

	// 获取文件
	content, err := facades.Storage().Get("common/hello.txt")
	if err != nil {
		panic(err.Error())
	}
	fmt.Println(content)

	// facades.Storage().Missing("common/hello.txt") 文件不存在
	fileExist := facades.Storage().Exists("common/hello.txt")
	if fileExist {
		fmt.Println("文件存在")
	}

	return ctx.Response().Json(http.StatusOK, http.Json{
		"cache": "cache",
	})
}

// 缓存
func (c *SqqqController) Cacheplay(ctx http.Context) http.Response {
	// ##################增加
	// 1.0 指定时间
	err := facades.Cache().Store("redis").Put("name", "15811448243", 5*time.Minute)
	if err != nil {
		panic(err.Error())
	}
	// 1.1, 永久保存
	err2 := facades.Cache().Store("redis").Put("age", 32, 0)
	if err2 != nil {
		panic(err2.Error())
	}
	// 1.2, 不存在则添加
	hasAdd := facades.Cache().Store("redis").Add("age", 32, 0)
	fmt.Println(hasAdd)

	// 1.3 永久添加
	hasAdd2 := facades.Cache().Forever("goravel", "value")
	fmt.Println(hasAdd2)

	// ##################获取
	value1 := facades.Cache().Get("goravel", "default")
	value2 := facades.Cache().GetInt("goravel", 1)
	value3 := facades.Cache().GetBool("goravel", false)
	value4 := facades.Cache().GetString("goravel", "default")
	fmt.Println(value1, value2, value3, value4)

	// ##################删除
	hasDel := facades.Cache().Forget("goravel") // 删除指定key
	fmt.Println(hasDel)

	hasFlush := facades.Cache().Flush() // 清空所有
	fmt.Println(hasFlush)

	// ##################其它
	value := facades.Cache().Pull("goravel", "") // 获取并删除
	fmt.Println(value)

	// get_add
	value5, err := facades.Cache().Remember("goravel", 5*time.Second, func() (any, error) {
		return "goravel", nil
	})
	if err != nil {
		panic(err.Error())
	}
	fmt.Println(value5)

	// 自增自减
	facades.Cache().Increment("key", 1)
	facades.Cache().Decrement("key", 2)

	// 是否存在
	facades.Cache().Has("key")

	// 锁
	lock := facades.Cache().Lock("foo", 10*time.Second)
	if lock.Get() {
		// 锁定 10 秒...

		lock.Release()
	}

	return ctx.Response().Json(http.StatusOK, http.Json{
		"cache": "cache",
	})
}

// 队列
func (c *SqqqController) Queue(ctx http.Context) http.Response {

	// 异步队列
	err := facades.Queue().Job(&jobs.CancelOrder{}, []queue.Arg{
		{Type: "int", Value: 1},
	}).
		Delay(time.Now().Add(10 * time.Second)).
		Dispatch()

	// 同步队列
	// err := facades.Queue().Job(&jobs.CancelOrder{}, []queue.Arg{}).DispatchSync()
	if err != nil {
		fmt.Println("error", err.Error())
	}

	return ctx.Response().Json(http.StatusOK, http.Json{
		"queue": "run",
	})
}

// 发送邮件
func (c *SqqqController) Sendmail(ctx http.Context) http.Response {

	// 正常发送邮件
	err := facades.Mail().To([]string{"1046457211@qq.com"}).Attach([]string{"./public/dog.jpeg"}).Content(mail.Content{
		Subject: "hello, goravel",
		Html:    "<h1>hello ,goralvel from client.</h1>",
	}).Send()

	// 队列发送邮件
	// err2 := facades.Mail().To([]string{"1046457211@qq.com"}).Attach([]string{"./public/dog.jpeg"}).Content(mail.Content{
	// 	Subject: "hello, goravel",
	// 	Html:    "<h1>hello ,goralvel from client.</h1>",
	// }).Queue(&mail.Queue{Connection:"high", Queue:"mail"})

	if err != nil {
		panic(err.Error())
	}

	return ctx.Response().Json(http.StatusOK, http.Json{
		"token": "email sended",
	})
}

// 辅助函数
func (c *SqqqController) Helper(ctx http.Context) http.Response {
	// path.App()  app 目录的路径
	path1 := path.App()
	path2 := path.App("http/controllers/base_controller.go")

	// path.Base()返回项目根目录的路径
	base1 := path.Base()

	//config
	conf1 := path.Config()
	conf2 := path.Config("app.go")

	// database path
	dbpath1 := path.Database()
	dbpath2 := path.Database("factories/user_factory.go")

	// storage
	storage1 := path.Storage()
	storage2 := path.Storage("app/file.txt")

	// public
	pub1 := path.Public()
	pub2 := path.Public("css/app.css")

	// 时间日期
	now := carbon.Now()
	now2 := carbon.Parse("2020-08-05 13:14:15")
	now3 := carbon.FromTimestamp(1577836800)

	// debug
	// debug.Dump("v1", "v2", "v3") // 打印任意对象
	// debug.FDump("v1", "v2", "V3")
	debug.SDump(now, now2, now3) // 打印输出至字符串

	return ctx.Response().Json(http.StatusOK, http.Json{
		"now3":     now3,
		"now2":     now2,
		"now":      now,
		"path1":    path1,
		"path2":    path2,
		"base1":    base1,
		"conf1":    conf1,
		"conf2":    conf2,
		"dbpath1":  dbpath1,
		"dbpath2":  dbpath2,
		"storage1": storage1,
		"storage2": storage2,
		"pub1":     pub1,
		"pub2":     pub2,
	})
}

// 加密解密
func (c *SqqqController) Jwttoken(ctx http.Context) http.Response {

	// 1, 根据用户信息生成token
	user := models.User{
		//		ID:    1023,
		Name:  "sbjsw",
		Phone: "15811448243",
		Email: "1046457211@qq.com",
		Age:   23,
	}

	user.ID = 123

	token, err := facades.Auth().Login(ctx, &user)
	if err != nil {
		panic(err.Error())
	}

	// 2.根据用户id生成token
	token2, err := facades.Auth().LoginUsingID(ctx, 3424)
	if err != nil {
		panic(err.Error())
	}

	// 3.token解析
	payload, err := facades.Auth().Parse(ctx, token)
	if err != nil {
		if errors.Is(err, auth.ErrorParseTokenFirst) {
			return ctx.Response().Json(http.StatusOK, http.Json{
				"error": "token expired",
			})
		}
		panic(err.Error())
	}
	/*
			"payload": {
		        "Guard": "user",
		        "Key": "123", // 用户ID
		        "ExpireAt": "2024-03-03T10:34:37+08:00",
		        "IssuedAt": "2024-03-03T09:34:37+08:00"
		    }
	*/

	// 4.token刷新
	new_token, err := facades.Auth().Refresh(ctx)

	// 5.退出登录
	err2 := facades.Auth().Logout(ctx)
	if err2 != nil {
		panic(err2.Error())
	}

	return ctx.Response().Json(http.StatusOK, http.Json{
		"token":     "Bearer " + token,
		"token2":    "Bearer " + token2,
		"payload":   payload,
		"new_token": new_token,
	})
}

// 加密解密
func (c *SqqqController) Encrypted(ctx http.Context) http.Response {
	// 字符串加密
	secret_str, err := facades.Crypt().EncryptString("goravel")
	if err != nil {
		panic(err.Error())
	}

	// 字符串解密
	original_str, err := facades.Crypt().DecryptString(secret_str)
	if err != nil {
		panic(err.Error())
	}

	return ctx.Response().Json(http.StatusOK, http.Json{
		"加密字符串": secret_str,
		"解密字符串": original_str,
	})
}

// hash加密
func (c *SqqqController) Hash(ctx http.Context) http.Response {
	// 密码加密
	password, err := facades.Hash().Make("123456")
	if err != nil {
		panic(err.Error())
	}

	// 密码比较
	if facades.Hash().Check("123456", password) {
		fmt.Println("密码一样")
	} else {
		fmt.Println("密码不一样")
	}

	return ctx.Response().String(http.StatusOK, password)
}

// 日志打印
func (c *SqqqController) LogPrint(ctx http.Context) http.Response {
	facades.Log().WithContext(ctx).Info("hello")
	facades.Log().Infof("hello", http.Json{"name": "sbjw"})

	return ctx.Response().String(http.StatusOK, "hello, golang")
}

// Response响应
func (c *SqqqController) ResponsePlayer(ctx http.Context) http.Response {
	// 文本响应
	return ctx.Response().String(http.StatusOK, "hello, golang")

	// json
	// return ctx.Response().Json(http.StatusOK, http.Json{
	// 	"name": "111",
	// })

	// json2
	// persons := struct {
	// 	ID   uint   `json:"id"`
	// 	Name string `json:"name"`
	// }{
	// 	ID:   1,
	// 	Name: "sb",
	// }
	// return ctx.Response().Json(http.StatusOK, persons)

	// 文件下载
	// return ctx.Response().File("./public/小程序.pdf")
}

// Request请求
func (c *SqqqController) RequestPlayer(ctx http.Context) http.Response {
	// 获取请求路径: /sqqq/req
	req_path := ctx.Request().Path()

	// 请求url: /sqqq/req?a=1
	req_url := ctx.Request().Url()

	// 请求host: localhost:3000
	req_host := ctx.Request().Host()

	// 完整请求地址： http://localhost:3000/sqqq/req?a=1
	req_fullhost := ctx.Request().FullUrl()

	// 请求方法: get
	req_method := ctx.Request().Method()

	// 请求头: headers
	req_headers := ctx.Request().Headers()
	req_header := ctx.Request().Header("User-Agent", "chrome")

	// ip地址
	req_ip := ctx.Request().Ip()

	// data
	req_data := ctx.Request().All()

	req_querys := ctx.Request().Queries()

	req_query := ctx.Request().Query("a", "")
	req_int := ctx.Request().QueryInt("a", 0)

	return ctx.Response().Json(http.StatusOK, http.Json{
		"req_int":      req_int,
		"req_query":    req_query,
		"req_querys":   req_querys,
		"req_path":     req_path,
		"req_url":      req_url,
		"req_host":     req_host,
		"req_fullhost": req_fullhost,
		"req_method":   req_method,
		"req_headers":  req_headers,
		"req_header":   req_header,
		"req_ip":       req_ip,
		"req_data":     req_data,
	})
}

// 文件下载
func (c *SqqqController) Download(ctx http.Context) http.Response {
	file := "./public/小程序.pdf"
	return ctx.Response().Download(file, "小程序.pdf")
}

func (c *SqqqController) List(ctx http.Context) http.Response {
	var userList []models.User
	facades.Orm().Query().Get(&userList)

	// struct转json
	jsonData, err := json.Marshal(userList)

	if err != nil {
		return ctx.Response().Json(http.StatusInternalServerError, http.Json{
			"error": err.Error(),
		})
	}
	return ctx.Response().String(http.StatusOK, string(jsonData))
}

func (c *SqqqController) Create(ctx http.Context) http.Response {
	return ctx.Response().Success().Json(http.Json{"hello": "golang"})
}

func (c *SqqqController) Update(ctx http.Context) http.Response {
	return ctx.Response().Success().Json(http.Json{"hello": "golang"})
}

func (c *SqqqController) Destroy(ctx http.Context) http.Response {
	return ctx.Response().Success().Json(http.Json{"hello": "golang"})
}

// 请求和响应
func (c *SqqqController) Show(ctx http.Context) http.Response {
	// 返回字符串
	// return ctx.Response().String(http.StatusOK, "hello, golang")

	// 返回json1
	return ctx.Response().Success().Json(http.Json{"hello": "golang"})
}
